#include "include/Session.h"
#include "include/SessionManager.h"
#include "include/Singleton.h"

Session::Session(boost::asio::io_service &io_service)
	: _socket(io_service), logic(io_service)
{
	memset(_package, '\0', sizeof(_package));
}

Session::~Session()
{
}

tcp::socket & Session::Socket()
{
	return _socket;
}

void Session::Start()
{
	_is_control = 0;
	
	_socket.async_read_some(boost::asio::buffer(_package, MAX_PACKAGE_SIZE),
		boost::bind(&Session::HandleRead, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}

void Session::StartControl()
{
	_is_control = 1;

	_socket.async_read_some(boost::asio::buffer(_package, MAX_PACKAGE_SIZE),
		boost::bind(&Session::HandleRead, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}

void Session::HandleWrite(const boost::system::error_code &error)
{
	if(error)
	{
		//DeleteSelf();
		std::cout << "error in Session::HandleWrite" << std::endl;
		return;
	}

	_socket.async_read_some(boost::asio::buffer(_package, MAX_PACKAGE_SIZE),
		boost::bind(&Session::HandleRead, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}

void Session::HandleRead(const boost::system::error_code &error, size_t bytes_transferred)
{
	if(error)
	{
		//DeleteSelf();
		std::cout << "error in Session" << std::endl;
		return;
	}

	_package_len = (int)bytes_transferred;

	// debug
	std::cout << "before process, recv msg len:" << _package_len << "content:" << std::endl;
	for(int i = 0; i < _package_len; i++)
	{
		std::cout << _package[i];
	}
	std::cout << std::endl;
	std::cout << "msg end." << std::endl;
	// debug end

	LogicResult result = logic.ProcessUpStreamData(_package, _package_len);
	// debug
	std::cout << "recv msg:" << std::endl;
	for(int i = 0; i < _package_len; i++)
	{
		std::cout << _package[i];
	}
	std::cout << std::endl;
	std::cout << "msg end." << std::endl;
	// debug end

	switch(result)
	{
	case LogicError:
		// debug
		std::cout << "logic error" << std::endl;
		// debug end
		//DeleteSelf();
		return;

	case LogicNeedConnect:
		// debug
		std::cout << "need connect" << std::endl;
		// debug end
		Singleton<SessionManager>::instance().AddSession(this);

		logic.p_client->socket.async_connect(*(logic.p_client->p_endpoint),
			boost::bind(&Session::HandleBackServerConnect, this, boost::asio::placeholders::error));

		break;

	case LogicNeedWrite:
		// debug
		std::cout << "need write" << std::endl;
		// debug end
		WriteToBackServer();
		break;

    default:
        break;
	}
}

void Session::WriteToBackServer()
{
	boost::asio::async_write(logic.p_client->socket, boost::asio::buffer(_package, _package_len),
		boost::bind(&Session::HandleBackServerWrite, this, boost::asio::placeholders::error));
}

void Session::HandleBackServerConnect(const boost::system::error_code& error)
{
	if(error)
	{
		// debug
		std::cout << "Connect GameServer Error" << std::endl;
		// debug end
		return;
	}

	logic.p_client->is_connect = true;

	WriteToBackServer();
}

void Session::HandleBackServerRead(const boost::system::error_code &error, size_t bytes_transferred)
{
	cout << "get package from game server, len: " << bytes_transferred << endl;
	cout << "package content: " << endl;
	for(int i = 0; i < bytes_transferred; i++)
	{
		cout << (char)(*(_package + i));
	}
	cout << endl;

	if(error)
	{
		cout << "error in " << __FUNCTION__ << endl;
		//DeleteSelf();
		return;
	}

	_package_len = (int)bytes_transferred;

	LogicResult result;
	char *p_data;
	int len;

	int num = logic.GetPackageNum(_package, _package_len);

	cout << "package num: " << num << endl;

	for(int i = 0; i < num; i++)
	{
		result = logic.ProcessDownStreamPackage(i, p_data, len);

		switch(result)
		{
		case LogicError:
			//DeleteSelf();
			std::cout << "return error in logic.ProcessDownStreamPackage" << std::endl;
			return;

		case LogicNormalData:
			boost::asio::async_write(_socket, boost::asio::buffer(p_data, len),
				boost::bind(&Session::HandleWrite, this, boost::asio::placeholders::error));

			//debug
			std::cout << "send data to client" << std::endl;
			// debug end
			break;

		case LogicBroadcastData:
		{
			Session *p_session;
			int key = logic.server_key;

			for(p_session = Singleton<SessionManager>::instance().GetFirstSession(key); p_session != NULL;
				p_session = Singleton<SessionManager>::instance().GetNextSession())
			{
				boost::asio::async_write(p_session->Socket(), boost::asio::buffer(p_data, len),
					boost::bind(&Session::HandleWrite, p_session, boost::asio::placeholders::error));
			}
		}
			break;

		case LogicMulticastData:
		{
			//debug
			std::cout << "send data to multi client" << std::endl;
			// debug end
			
			Session *p_session;
			int key = logic.server_key;
			unsigned int *p_player_id = logic.p_multicast_player_id;
			int valid_package_len = len - logic.drop_info_len;

			std::cout << "multicast_player_num: " << logic.multicast_player_num << endl;
			for(int i = 0; i < logic.multicast_player_num; i++)
			{
				p_session = Singleton<SessionManager>::instance().GetSession(key, *p_player_id);

				if(NULL == p_session)
				{
					continue;
				}

				//debug
				std::cout << "send multi data to client: " << *p_player_id << std::endl;
				// debug end
				
				p_player_id++;

				boost::asio::async_write(p_session->Socket(), boost::asio::buffer(
					p_data, valid_package_len),
					boost::bind(&Session::HandleWrite, p_session, boost::asio::placeholders::error));
			}
		}
			break;

		default:
			break;
		}
	}
}

void Session::HandleBackServerWrite(const boost::system::error_code& error)
{
	logic.p_client->socket.async_read_some(boost::asio::buffer(_package, MAX_PACKAGE_SIZE),
		boost::bind(&Session::HandleBackServerRead, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}

void Session::DeleteSelf()
{
	std::cout << "delete self" << std::endl;
	Singleton<SessionManager>::instance().DelSession(this);
	delete this;
}
